/**
 * 权限验证中间件模块
 * 提供权限验证功能，确保用户具有执行特定操作的权限
 */

// - 自助类：用户对自身资源的操作（改密码、上传头像、查看自己的菜单/权限），仅认证即可，严格“只能操作自己”。
// - 管理类：管理员对他人或系统的治理动作（重置密码、分配角色、配置菜单/权限），需明确权限码或权限层级。
// - 公共认证类：所有登录用户可调用的基础接口（如获取个人信息、刷新 token），不进入权限表、只需认证。
// - 数据域类：依赖数据范围限制的业务查询，受 role.data_scope/data_scope_dept_ids 约束。
// - 系统配置类：高敏系统配置接口，仅 permission_level >= 40 或明确权限码。
// - 审计/安全类：涉及敏感行为（删除、批量变更），建议权限码 + 审计记录。


const { getLogger } = require('../logger');
const logger = getLogger('middlewares.permissionMiddleware');
const { serverError, forbidden } = require('../utils/response');
const cacheService = require('../cache');
const { getDbPool } = require('../infra/dbClient');
const db = getDbPool();
const { isSuperAdmin, getUserRolesWithCache } = require('../utils/utils');
const PermissionModel = require('../models/permissionModel');
const DepartmentModel = require('../models/departmentModel');

// getUserRolesWithCache函数已从utils.js导入，不需要在此重复声明
      
/**
 * 权限验证中间件工厂函数
 * @param {Array|String} requiredPermissions - 必需的权限码，可以是字符串或数组
 * @param {Object} options - 选项配置
 * @param {Boolean} options.checkDataPermission - 是否同时检查数据权限
 * @param {String} options.dataPermissionType - 数据权限类型
 */
const checkPermission = (requiredPermissions, options = {}) => {
  const { checkDataPermission = false, dataPermissionType = 'read' } = options;
  const permissions = Array.isArray(requiredPermissions) ? requiredPermissions : [requiredPermissions];
  
  return async (req, res, next) => {
    try {
      // 确保用户已通过身份验证
      if (!req.user || !req.user.id) {
        return forbidden(req, res, '请先登录');
      }
      
      // 检查用户是否为超级管理员，如果是则直接跳过权限验证
      logger.info('开始权限验证', { userId: req.user.id, userData: req.user });
      let userRoles = await getUserRolesWithCache(req.user.id, db, logger);
      // 如果用户拥有super_admin角色，则跳过权限验证（超级管理员特权）
      const hasSuperAdminRole = isSuperAdmin(userRoles);
      logger.info('检查超级管理员角色', { userId: req.user.id, roles: userRoles, hasSuperAdmin: hasSuperAdminRole });
      if (hasSuperAdminRole) {
        logger.info('超级管理员权限验证跳过', { userId: req.user.id });
        return next();
      }
      
      // 获取用户拥有的权限码
      let userPermissionCodes;
      try {
        // 优先从permissionModel获取权限码
        userPermissionCodes = await PermissionModel.getPermissionCodesByUserId(req.user.id);
      } catch (error) {
        // 降级方案：从新的缓存服务获取权限
        logger.warn('从PermissionModel获取权限失败，降级到缓存机制', { userId: req.user.id, error: error });
        let userPermissions = await cacheService.get(`permission_codes:user:${req.user.id}`);
        
        // 缓存未命中时从数据库获取并更新缓存
        if (!userPermissions) {
          logger.info('权限缓存未命中，从数据库加载', { userId: req.user.id });
          
          // 获取用户所有权限代码（包括继承的权限）
          const sql = `
            SELECT DISTINCT p.permission_code 
            FROM permission p
            INNER JOIN role_permission rp ON p.id = rp.permission_id
            INNER JOIN user_role ur ON rp.role_id = ur.role_id
            WHERE ur.user_id = ? AND p.permission_code IS NOT NULL AND p.permission_code != '' AND p.is_delete = 0 AND p.status = 1
          `;
          
          const [rows] = await db.execute(sql, [req.user.id]);
          userPermissions = rows.map(row => row.permission_code);
          
          // 缓存用户权限，设置合理的过期时间（5分钟）
          await cacheService.set(`permission_codes:user:${req.user.id}`, userPermissions, 300);
        }
        userPermissionCodes = userPermissions;
      }
      
      // 检查是否拥有所需权限
      const hasPermission = permissions.some(permission => 
        userPermissionCodes.includes(permission)
      );
      
      if (hasPermission) {
        logger.info('权限验证通过', { userId: req.user.id, requiredPermissions: permissions });
        
        // 如果需要检查数据权限
        if (checkDataPermission) {
          // 基于角色的 data_scope / data_scope_dept_ids 计算数据权限
          const deptId = req.query.dept_id || req.body.dept_id || req.params.dept_id;
          const [userDeptRows] = await db.execute('SELECT department_id FROM user WHERE id = ? AND is_delete = 0', [req.user.id]);
          const userDeptId = userDeptRows?.[0]?.department_id || null;

          const [roleRows] = await db.execute(`
            SELECT r.data_scope, r.data_scope_dept_ids 
            FROM role r 
            INNER JOIN user_role ur ON r.id = ur.role_id 
            WHERE ur.user_id = ? AND r.is_delete = 0 AND r.status = 0
          `, [req.user.id]);

          let fullAccess = roleRows.some(r => Number(r.data_scope) === 1);
          let accessibleDeptIds = new Set();

          if (!fullAccess) {
            for (const r of roleRows) {
              const scope = Number(r.data_scope);
              if (scope === 3) {
                if (userDeptId) accessibleDeptIds.add(Number(userDeptId));
              } else if (scope === 2) {
                if (userDeptId) {
                  accessibleDeptIds.add(Number(userDeptId));
                  try {
                    const children = await DepartmentModel.getAllChildren(Number(userDeptId));
                    for (const c of children) accessibleDeptIds.add(Number(c.id));
                  } catch (e) {}
                }
              } else if (scope === 5) {
                const ids = (r.data_scope_dept_ids || '').split(',').map(s => Number(s.trim())).filter(n => !isNaN(n) && n > 0);
                ids.forEach(n => accessibleDeptIds.add(n));
              } else if (scope === 4) {
                // 仅自己数据：在部门维度上仅允许自己的部门
                if (userDeptId) accessibleDeptIds.add(Number(userDeptId));
              }
            }
          }

          if (deptId) {
            const targetDeptId = Number(deptId);
            const allowed = fullAccess || accessibleDeptIds.has(targetDeptId);
            if (!allowed) {
              logger.warn('数据访问权限不足', { userId: req.user.id, deptId: targetDeptId, permissionType: dataPermissionType });
              return forbidden(req, res, '数据访问权限不足');
            }
          }

          req.dataPermission = {
            userId: req.user.id,
            permissionType: dataPermissionType,
            accessibleDeptIds: fullAccess ? 'ALL' : Array.from(accessibleDeptIds),
            dataScopeFullAccess: fullAccess,
            userDeptId
          };
        }
        
        return next();
      }
      
      logger.warn('权限验证失败', { userId: req.user.id, requiredPermissions: permissions });
      return forbidden(req, res, '权限不足，无法执行此操作');
    } catch (error) {
      logger.error('权限验证过程中发生错误', { userId: req.user.id, error: error });
      return serverError(req, res, '权限验证错误');
    }
  };
};

/**
 * 角色验证中间件
 * @param {string|Array<string>} requiredRoles - 所需的角色代码或角色代码数组
 * @returns {Function} 中间件函数
 */
const checkRole = (requiredRoles) => {
  return async (req, res, next) => {
    try {
      if (!req.user || !req.user.id) {
        return forbidden(req, res, '请先登录');
      }

      // 从缓存获取用户角色
      let userRoles = await getUserRolesWithCache(req.user.id, db, logger);
      
      // 如果用户拥有super_admin角色，则跳过角色验证（超级管理员特权）
      const hasSuperAdminRole = isSuperAdmin(userRoles);
      if (hasSuperAdminRole) {
        logger.info('超级管理员角色验证跳过', { userId: req.user.id });
        return next();
      }
      
      // 注意：userRoles是对象数组，需要提取code属性进行比较
      const hasRole = Array.isArray(requiredRoles)
        ? requiredRoles.some(requiredRole => userRoles.some(userRole => userRole.code === requiredRole))
        : userRoles.some(userRole => userRole.code === requiredRoles);
      
      if (hasRole) {
        return next();
      }
      
      return forbidden(req, res, '角色不足，无法执行此操作');
    } catch (error) {
      logger.error('角色验证过程中发生错误', { userId: req.user.id, error: error });
      return serverError(req, res, '角色验证错误');
    }
  };
};

/**
 * 超级管理员验证中间件
 * @returns {Function} 中间件函数
 */
const checkSuperAdmin = () => {
  return checkRole('SUPER_ADMIN'); // 超级管理员角色代码为'SUPER_ADMIN'
};

/**
 * 权限层级验证中间件
 * @param {Number} minLevel - 最小权限层级要求
 */
const checkPermissionLevel = (minLevel) => {
  return async (req, res, next) => {
    try {
      if (!req.user || !req.user.id) {
        return forbidden(req, res, '请先登录');
      }

      // 检查是否是超级管理员
      let userRoles = await getUserRolesWithCache(req.user.id, db, logger);
      const hasSuperAdminRole = isSuperAdmin(userRoles);
      if (hasSuperAdminRole) {
        logger.info('超级管理员权限层级验证跳过', { userId: req.user.id });
        return next();
      }

      // 查询用户的最大权限层级
      const query = `
        SELECT MAX(r.permission_level) as max_level 
        FROM user_role ur
        JOIN role r ON ur.role_id = r.id
        WHERE ur.user_id = ?
      `;
      
      const [results] = await db.execute(query, [req.user.id]);
      const userMaxLevel = results[0].max_level || 0;
      
      if (userMaxLevel < minLevel) {
        logger.warn('权限层级不足', { userId: req.user.id, requiredLevel: minLevel, actualLevel: userMaxLevel });
        return forbidden(req, res, '权限层级不足');
      }

      logger.info('权限层级验证通过', { userId: req.user.id, requiredLevel: minLevel, actualLevel: userMaxLevel });
      next();
    } catch (error) {
      logger.error('权限层级检查错误:', { userId: req.user.id, error: error });
      return serverError(req, res, '服务器内部错误');
    }
  };
};



/**
 * 允许“查看自己的”或具备指定权限/权限层级的用户访问
 * @param {String} requiredPermission 指定的权限码
 * @param {Object} options 配置参数
 * @param {String} options.paramKey 路由参数中的用户ID字段，默认'id'
 * @param {Number} options.minLevel 具备访问他人所需的最小权限层级，默认20
 */
const checkSelfOrPermission = (requiredPermission, options = {}) => {
  const { paramKey = 'id', minLevel = 40 } = options;

  return async (req, res, next) => {
    try {
      if (!req.user || !req.user.id) {
        return forbidden(req, res, '请先登录');
      }

      // 超级管理员放行
      const roles = await getUserRolesWithCache(req.user.id, db, logger);
      if (isSuperAdmin(roles)) {
        return next();
      }

      // 自己查看自己的信息放行
      const targetUserId = Number(req.params?.[paramKey] || req.query?.[paramKey] || req.body?.[paramKey]);
      if (!isNaN(targetUserId) && targetUserId === Number(req.user.id)) {
        return next();
      }

      // 权限码检查
      const codes = await PermissionModel.getPermissionCodesByUserId(req.user.id);
      if (codes.includes(requiredPermission)) {
        return next();
      }

      const [userDeptRows] = await db.execute('SELECT department_id FROM user WHERE id = ? AND is_delete = 0', [req.user.id]);
      const userDeptId = userDeptRows?.[0]?.department_id || null;
      const [roleRows] = await db.execute(`
        SELECT r.data_scope, r.data_scope_dept_ids 
        FROM role r 
        INNER JOIN user_role ur ON r.id = ur.role_id 
        WHERE ur.user_id = ? AND r.is_delete = 0 AND r.status = 0
      `, [req.user.id]);
      let fullAccess = roleRows.some(r => Number(r.data_scope) === 1);
      let accessibleDeptIds = new Set();
      if (!fullAccess) {
        for (const r of roleRows) {
          const scope = Number(r.data_scope);
          if (scope === 3) {
            if (userDeptId) accessibleDeptIds.add(Number(userDeptId));
          } else if (scope === 2) {
            if (userDeptId) {
              accessibleDeptIds.add(Number(userDeptId));
              try {
                const children = await DepartmentModel.getAllChildren(Number(userDeptId));
                for (const c of children) accessibleDeptIds.add(Number(c.id));
              } catch (e) {}
            }
          } else if (scope === 5) {
            const ids = (r.data_scope_dept_ids || '').split(',').map(s => Number(s.trim())).filter(n => !isNaN(n) && n > 0);
            ids.forEach(n => accessibleDeptIds.add(n));
          } else if (scope === 4) {
            if (userDeptId) accessibleDeptIds.add(Number(userDeptId));
          }
        }
      }
      if (!isNaN(targetUserId)) {
        const [targetRows] = await db.execute('SELECT department_id FROM user WHERE id = ? AND is_delete = 0', [targetUserId]);
        const targetDeptId = targetRows?.[0]?.department_id || null;
        const allowedByDept = fullAccess || (targetDeptId && accessibleDeptIds.has(Number(targetDeptId)));
        if (allowedByDept) {
          return next();
        }
      }
      const levelSql = `
        SELECT MAX(r.permission_level) as max_level 
        FROM user_role ur 
        JOIN role r ON ur.role_id = r.id 
        WHERE ur.user_id = ?
      `;
      const [rows] = await db.execute(levelSql, [req.user.id]);
      const userMaxLevel = rows?.[0]?.max_level || 0;
      if (userMaxLevel >= minLevel) {
        return next();
      }

      return forbidden(req, res, '权限不足，无法执行此操作');
    } catch (error) {
      logger.error('自助或权限验证错误', { userId: req.user?.id, error: error });
      return serverError(req, res, '权限验证错误');
    }
  };
};


module.exports = { checkSelfOrPermission, checkPermission, requirePermission: checkPermission, checkRole, checkSuperAdmin, checkPermissionLevel, getUserRolesWithCache };